// ttt project main.go
package main

import (
	utils "bitbucket.org/weager/utils"
	//"funny/db"
	"log"
	"net"

	"github.com/astaxie/beego/orm"
	_ "github.com/go-sql-driver/mysql"
	"time"
)

//========================================================================
// 协议格式：
//
// 目前控制udp单个数据包的载荷为548字节（因为标准的MTU为576字节，IP层头20字节，UDP头8字节）
// 请求载荷数据大小：sequence为8bits，则一个请求最大发送数据为：2^8*548字节
//
// version：8 bits
// operate：8 bits
// sequence: 8 bits
// total sequence：8 bits
// ID：64 bits   （08618668204095，前三位为国际区号，后11位为手机号）
// content：。。。。
//========================================================================

// 协议版本: version
const (
	VERSION_0 = iota //目前是这个版本
	VERSION_1
	VERSION_2
	VERSION_3
	VERSION_4
	VERSION_5
	VERSION_6
	VERSION_7
)

// 支持的操作: operator
const (
	OP_0 = iota // get next item
	OP_1
	OP_2
	OP_3
	OP_4
	OP_5
	OP_6
	OP_7
)

//  协议的前96 bits（12 byte），固定的协议头，不管版本是哪个，这部分头格式不变
type ReqHeader struct {
	V        byte   // version, 4 bits
	Op       byte   // operator, 4 bits
	Seq      byte   // sequence, 8 bits
	TotalSeq byte   // total sequence, 8 bits
	Id       uint64 // user id, 64 bits
}

// 针对某个版本协议的处理器
type VersinoHandler func(conn *net.UDPConn, remoteAddr *net.UDPAddr, reqHeader *ReqHeader, content []byte)

// 这里存放所有的版本协议处理器
var handlers map[byte]VersinoHandler

// 把所有的版本处理器注册到一个map中
func init() {
	initDB()
	handlers = make(map[byte]VersinoHandler)
	handlers[VERSION_0] = version0Handler
}

func main() {
	udpAddr, err := net.ResolveUDPAddr("udp", ":12345")
	utils.CheckErr(err, log.Fatal)
	conn, err := net.ListenUDP("udp", udpAddr)
	utils.CheckErr(err, log.Fatal)

	for {
		// 固定的协议头，不管版本是哪个，这部分头格式不变
		var bytes []byte = make([]byte, 548)
		count, remoteAddr, err := conn.ReadFromUDP(bytes)
		utils.CheckErr(err, log.Println)
		log.Println("request byte count:", count)
		log.Println("bytes:", bytes)
		log.Println("address:", remoteAddr)

		header, content := parseHeader(bytes, count)
		log.Println(content)
		go handlers[header.V](conn, remoteAddr, header, content)

		if x := recover(); x != nil {
			log.Printf("run time panic: %v", x)
		}
	}
}

// 解析协议头
func parseHeader(bytes []byte, count int) (req *ReqHeader, content []byte) {
	// 如果header不是12个byte，说明请求的格式不对
	if count < 12 {
		panic("protocol header is short")
	}
	v := bytes[0]
	op := bytes[1]
	seq := bytes[2]
	totalSeq := bytes[3]
	id := utils.ByteToUint64(bytes[4:12])
	return &ReqHeader{v, op, seq, totalSeq, id}, bytes[12:count]
}

// version 0 的请求处理器
func version0Handler(conn *net.UDPConn, remoteAddr *net.UDPAddr, header *ReqHeader, content []byte) {
	var resp string
	switch header.Op {
	case OP_0:
		resp = getNext(header.Id, utils.ByteToUint64(content))
	}
	log.Println("request content byte:", content)
	count, err := conn.WriteTo([]byte(resp), remoteAddr)
	utils.CheckErr(err, log.Println)
	log.Println("response byte count:", count)
	log.Println("response content:", resp)
}

// 获取下一个条目（可以是笑话）
func getNext(id uint64, prev uint64) string {
	log.Println("prev id: ", prev)
	return GetNextTextJoke(prev)
}

var o orm.Ormer

func initDB() {
	orm.Debug = true
	orm.RegisterDriver("mysql", orm.DR_MySQL)
	orm.RegisterModel(new(Txtjoke))
	orm.RegisterDataBase("default", "mysql", "root:root@tcp(127.0.0.1:3306)/funny?charset=utf8")
	o = orm.NewOrm()
	err := o.Using("default") // 默认使用 default，你可以指定为其他数据库
	utils.CheckErr(err, log.Println)
}

type Txtjoke struct {
	Seq     uint64 `orm:"pk;auto;unique;NOT NULL"`
	Uid     uint64 `orm:"unique"`
	Context string
	Lmt     time.Time
}

func GetNextTextJoke(uid uint64) string {
	tmpModel := Txtjoke{Uid: uid}
	err := o.Read(&tmpModel, "uid")
	log.Print("read err: ")
	utils.CheckErr(err, log.Println)
	return tmpModel.Context
}
